﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

using IronPython.Hosting;
using IronPython.Runtime.Exceptions;
using IronPython.Modules;

using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace EuphoricEngine3D
{
    public class PythonInterpreter : DrawableGameComponent
    {
        const string Prompt = "> ";
        const string PromptCont = ">>";
        string multi;
        public Console Console;

        ClrModule clr;
        PythonEngine PythonEngine;
        MemoryStream PythonOutput;
        ASCIIEncoding ASCIIEncoder;

        public PythonInterpreter(Game game, SpriteFont font)
            : base(game)
        {
            this.PythonEngine = new PythonEngine();
            this.PythonOutput = new MemoryStream();
            this.PythonEngine.SetStandardOutput(PythonOutput);
            this.ASCIIEncoder = new ASCIIEncoding();

            clr = this.PythonEngine.Import("clr") as ClrModule;
            clr.AddReference("Microsoft.Xna.Framework");
            clr.AddReference("Microsoft.Xna.Framework.Game");
            clr.AddReference("EuphoricEngine3D");

            this.PythonEngine.Execute("from Microsoft.Xna.Framework import *");
            this.PythonEngine.Execute("from Microsoft.Xna.Framework.Graphics import *");
            this.PythonEngine.Execute("from Microsoft.Xna.Framework.Content import *");
            this.PythonEngine.Execute("from Microsoft.Xna.Framework.Media import *");
            this.PythonEngine.Execute("from Microsoft.Xna.Framework.Net import *");

            this.PythonEngine.Execute("from EuphoricEngine3D import *");
            this.PythonEngine.Execute("from EuphoricEngine3D.Events import *");
            this.PythonEngine.Execute("from EuphoricEngine3D.Components import *");
            this.PythonEngine.Execute("from EuphoricEngine3D.Extentions import *");
            this.PythonEngine.Execute("from EuphoricEngine3D.Helpers import *");
            this.PythonEngine.Execute("from EuphoricEngine3D.Helpers.Drawing import *");
            this.PythonEngine.Execute("from EuphoricEngine3D.Input import *");

            multi = "";
            Console = new Console(game, font);
            game.Components.Add(Console);
            Console.Prompt(Prompt, Execute);
            //AddGlobal("this", Console);
        }

        private string getOutput()
        {
            byte[] statementOutput = new byte[PythonOutput.Length];
            PythonOutput.Position = 0;
            PythonOutput.Read(statementOutput, 0, (int)PythonOutput.Length);
            PythonOutput.Position = 0;
            PythonOutput.SetLength(0);

            return ASCIIEncoder.GetString(statementOutput);
        }

        public void Execute(string input)
        {
            try
            {
                if ((input != "") && ((input[input.Length - 1].ToString() == ":") || (multi != "")))
                {
                    multi += input + "\n";
                    Console.Prompt(PromptCont, Execute);
                }
                else if (multi != "" && input == "")
                {
                    string temp = multi;
                    multi = "";
                    PythonEngine.Execute(temp);
                    Console.WriteLine(getOutput());
                    Console.Prompt(Prompt, Execute);
                }
                else
                {
                    PythonEngine.Execute(input);
                    Console.WriteLine(Console.Chomp(getOutput()));
                    Console.Prompt(Prompt, Execute);
                }
            }
            catch (Exception ex)
            {
                Console.WriteError("ERROR: " + ex.Message);
                Console.Prompt(Prompt, Execute);
            }

        }

        public void ImportNamespace(string nameSpace)
        {
            this.PythonEngine.Execute("from " + nameSpace + " import *");
        }

        public void AddReference(string reference)
        {
            clr.AddReference(reference);
        }

        public void AddGlobal(string name, object value)
        {
            PythonEngine.Globals.Add(name, value);
        }
    }
}
